/**
 * @author Haidar Osman
 */
var ModelManager = function(container, width, height) {
	var that = this;
	this.userName = "";
	this.stage = new Kinetic.Stage(container, width, height);
	this.models = [];
	this.currentModel = null;
	this.lastExecutedCommand = -1;
	this.switchModel = function(name) {
		var newModel = null;
		var i = 0;
		for( i = 0; i < this.models.length; i++) {
			if(that.models[i].name == name) {
				newModel = that.models[i];
				break;
			}
		}
		if(newModel != null) {
			//removing the old model views
			if(that.currentModel != null) {
				var views = that.currentModel.views;
				for( i = 0; i < views.length; i++) {
					that.stage.remove(views[i].layer);
				}
			}
			that.stage.clear();
			var views = newModel.views;

			for( i = 0; i < views.length; i++) {
				that.stage.add(views[i].layer);
			}
			var classes = newModel.classes;
			newModel.bindTreeEvents();
			newModel.bindReplayEvents();
			this.currentModel = newModel;
			this.currentModel.fillConsole();
			this.currentModel.fillChat();
			if(that.currentModel.currentView != null) {
				this.currentModel.switchView(that.currentModel.currentView.name);
			} else {
				if(that.currentModel.views.length > 0) {
					this.currentModel.switchView(that.currentModel.views[0].name);
				}
			}
			that.webSocket.emit("currentModel", {
				currentModel : name,
				userName : that.userName
			});

		}

	}
	this.getModelsList = function() {
		var i = 0;
		var results = [];
		for( i = 0; i < this.models.length; i++) {
			results[results.length] = {
				name : that.models[i].name
			};
		}
		return results;
	}
	this.getJSON = function() {
		var models = {
			models : [],
			currentModel : that.currentModel.name,
			currentView : that.currentModel.currentView.name
		};
		var i = 0;
		for( i = 0; i < that.models.length; i++) {
			models.models[i] = that.models[i].getJSON();
		}
		return models;
	}
	this.getModel = function(modelName) {
		var model = null;
		var i = 0;
		for( i = 0; i < this.models.length; i++) {
			if(that.models[i].name == modelName) {
				model = that.models[i];
				return model;
				break;
			}
		}
		return null;
	}

	this.loadJSON = function(JSON) {
		var i = 0;
		var j = 0;
		var k = 0;
		if(JSON.models) {
			// for( i = 0; i < 2; i++) {
			for( i = 0; i < JSON.models.length; i++) {
				//var newModel=new ViewManager(that.stage,JSON.models[i].name);

				that.addModel(JSON.models[i].name);
				var classes = JSON.models[i].classes;
				if(classes) {
					for( j = 0; j < classes.length; j++) {

						var classObj = new Class(classes[j].name);
						var atts = classes[j].atts;
						if(atts) {
							for( k = 0; k < atts.length; k++) {

								classObj.attributes.addMember(atts[k].name)
							}
						}

						var ms = classes[j].methods;
						if(ms) {
							for( k = 0; k < ms.length; k++) {
								classObj.methods.addMember(ms[k].name)
							}
						}
						that.currentModel.addClassObj(classObj);
					}
				}
				var relations = JSON.models[i].relations;
				if(relations) {

					for( j = 0; j < relations.length; j++) {

						that.currentModel.addRelation(that.currentModel.getClass(relations[j].from), that.currentModel.getClass(relations[j].to), relations[j].type);
						that.currentModel.relations.members[j].title = relations[j].title;
					}
				}
				var views = JSON.models[i].views;

				if(views) {
					for( j = 0; j < views.length; j++) {

						that.currentModel.addView(views[j].name);
						var classShapes = views[j].classes;
						if(classShapes) {
							for( k = 0; k < classShapes.length; k++) {

								var newClass = new ClassShape(parseInt(classShapes[k].x), parseInt(classShapes[k].y), that.currentModel.getClass(classShapes[k].classObj));
								that.currentModel.currentView.addClass(newClass);
								var isMethHidden = false;
								var isAttsHidden = false;
								if((classShapes[k].isMethodsHidden) && (classShapes[k].isAttsHidden) && (classShapes[k].scale)) {
									if(parseInt(classShapes[k].isMethodsHidden) == 1) {
										isMethHidden = true;
									}
									if(parseInt(classShapes[k].isAttsHidden) == 1) {
										isAttsHidden = true;
									}

									var scale = parseFloat(classShapes[k].scale);
									newClass.resetShapeFromJSON(scale, isAttsHidden, isMethHidden);
								}
								// newClass.updateFromJSON();
							}
						}
					}

				}
			}
		}
		if(JSON.currentModel) {
			that.switchModel(JSON.currentModel);
		}
		if(JSON.currentView) {
			that.currentModel.switchView(JSON.currentView);
		}
	}
	//List of commands taken from the user interface
	this.addModel = function(name, switchToNewModel, user) {
		this.models[this.models.length] = new ViewManager(this.stage, name, that);
		if(switchToNewModel)
			that.switchModel(name);
		var models = {};
		models.results = [];
		var i = 0;
		for( i = 0; i < this.models.length; i++) {
			models.results[models.results.length] = {
				name : that.models[i].name
			};
		}
		models.total = models.results.length;
		$('#modelList').empty();
		$('#modelList').flexbox(models, {
			allowInput : false,
			selectFirstMatch : false,
			width : 150,
			// showArrow:false,
			onSelect : function() {
				that.switchModel(this.value);
			}
		});
		var cmd = user + " has added a new model '" + name + "'.";
		cmd = "<li> <font color='green' size='3'>" + cmd + "</font></li>";
		for( i = 0; i < that.models.length; i++) {
			that.models[i].addConsoleString(cmd);
		}
	}
	this.addNewClassToView = function(modelName, viewName, x, y, className, user) {
		var model = this.getModel(modelName);
		x = parseFloat(x);
		y = parseFloat(y);
		model.addNewClassToView(viewName, x, y, className);
		if(!(that.isModelViewInFocus(model, model.getView(viewName)))) {
			that.highlightClass(modelName, className, user);
		}
		var cmd = user + " has added a new class '" + className + "'."
		cmd = "<li> <font color='green' size='2'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}
	this.removeClassFromModel = function(modelName, className, user) {
		var model = this.getModel(modelName);
		var cmd = user + " has removed the class '" + className + "' from the model."
		cmd = "<li > <font color='red' size='2'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
		model.removeClass(className);
		// this.getModel(modelName).removeClass(className);

	}
	this.renameClass = function(modelName, viewName, oldClassName, newClassName, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		view.getClass(oldClassName).renameClass(newClassName);
		var isInFocus = false;
		for( i = 0; i < model.views.length; i++) {
			classShape = model.views[i].getClass(newClassName);
			if(classShape) {
				if(that.isModelViewInFocus(model, model.views[i])) {
					that.unHighlightClass(modelName, newClassName);
					classShape.update();
					model.views[i].update();
					isInFocus = true;
				}
			}
		}
		if(!(isInFocus)) {
			that.highlightClass(modelName, newClassName, user);
		}
		var cmd = user + " has renamed class '" + oldClassName + "' to '" + newClassName + "'.";
		cmd = "<li > <font color='orange' size='2'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}
	this.isModelViewInFocus = function(model, view) {
		if(that.currentModel) {
			if(model.name == that.currentModel.name) {
				if(that.currentModel.currentView) {
					if(view.name == that.currentModel.currentView.name) {
						return true;
					}
				}
			}
		}
		return false;
	}
	this.removeClassFromView = function(modelName, viewName, className, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		view.removeClass(className);
		if(that.isModelViewInFocus(model, view)) {
			view.update();
		}

		that.unHighlightClass(modelName, className);
		var cmd = user + " has removed the class '" + className + "' from the view '" + viewName + "'.";
		cmd = "<li > <font color='red' size='2'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}

	this.addMethodToClass = function(modelName, viewName, className, methodName, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		var classShape = view.getClass(className);
		classShape.methods.addMember(methodName);

		var isInFocus = false;
		for( i = 0; i < model.views.length; i++) {
			classShape = model.views[i].getClass(className);
			if(classShape) {
				if(that.isModelViewInFocus(model, model.views[i])) {
					//that.unHighlightClass(modelName, newClassName);
					classShape.update();
					//view.update();
					isInFocus = true;
				}
			}
		}
		if(!(isInFocus)) {
			that.highlightMethod(modelName, className, methodName, user);
		}

		//
		// if(that.isModelViewInFocus(model, view)) {
		// classShape.update();
		// } else {
		// that.highlightMethod(modelName, className, methodName, user);
		// }

		// that.unHighlightClass(modelName, className);
		var cmd = user + " has added the method '" + methodName + "' to class '" + className + "'.";
		cmd = "<li > <font color='green' size='1'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}
	this.addAttToClass = function(modelName, viewName, className, attName, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		var classShape = view.getClass(className);
		classShape.attributes.addMember(attName);

		var isInFocus = false;
		for( i = 0; i < model.views.length; i++) {
			classShape = model.views[i].getClass(className);
			if(classShape) {
				if(that.isModelViewInFocus(model, model.views[i])) {
					//that.unHighlightClass(modelName, newClassName);
					classShape.update();
					//view.update();
					isInFocus = true;
				}
			}
		}
		if(!(isInFocus)) {
			that.highlightAttribute(modelName, className, attName, user);
		}

		// if(that.isModelViewInFocus(model, view)) {
		// classShape.update();
		// } else {
		// that.highlightAttribute(modelName, className, attName, user);
		// }

		// that.unHighlightClass(modelName, className);
		var cmd = user + " has added the attribute '" + attName + "' to class '" + className + "'.";
		cmd = "<li > <font color='green' size='1'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}
	this.removeMethodFromClass = function(modelName, viewName, className, methodName, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		var classShape = view.getClass(className);
		classShape.methods.removeMember(methodName);

		for( i = 0; i < model.views.length; i++) {
			classShape = model.views[i].getClass(className);
			if(classShape) {
				if(that.isModelViewInFocus(model, model.views[i])) {
					//that.unHighlightClass(modelName, newClassName);
					classShape.update();
					//view.update();
					// isInFocus = true;
				}
			}
		}
		//
		// if(that.isModelViewInFocus(model, view)) {
		// classShape.update();
		// }

		// that.unHighlightClass(modelName, className);
		var cmd = user + " has removed the method '" + methodName + "' from class '" + className + "'.";
		cmd = "<li > <font color='red' size='1'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}
	this.removeAttFromClass = function(modelName, viewName, className, attName, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		var classShape = view.getClass(className);
		classShape.attributes.removeMember(attName);

		for( i = 0; i < model.views.length; i++) {
			classShape = model.views[i].getClass(className);
			if(classShape) {
				if(that.isModelViewInFocus(model, model.views[i])) {
					//that.unHighlightClass(modelName, newClassName);
					classShape.update();
					//view.update();
					// isInFocus = true;
				}
			}
		}

		// if(that.isModelViewInFocus(model, view)) {
		// classShape.update();
		// }

		// that.unHighlightClass(modelName, className);
		var cmd = user + " has removed the attribute '" + attName + "' from class '" + className + "'.";
		cmd = "<li > <font color='red' size='1'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}
	this.renameMethodInClass = function(modelName, viewName, className, oldMethodName, newMethodName, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		var classShape = view.getClass(className);
		var method = classShape.methods.memberArray.getMember(oldMethodName);
		method.name = newMethodName;
		method.isHighlighted = false;

		// classShape.methods.getMember(oldMethodName).setName(newMethodName);

		var isInFocus = false;
		for( i = 0; i < model.views.length; i++) {
			classShape = model.views[i].getClass(className);
			if(classShape) {
				if(that.isModelViewInFocus(model, model.views[i])) {
					//that.unHighlightClass(modelName, newClassName);
					classShape.update();
					//view.update();
					isInFocus = true;
				}
			}
		}
		if(!(isInFocus)) {
			that.highlightMethod(modelName, className, newMethodName, user);
		}

		// if(that.isModelViewInFocus(model, view)) {
		// classShape.update();
		// } else {
		// that.highlightMethod(modelName, className, newMethodName, user);
		// }

		// that.unHighlightClass(modelName, className);
		var cmd = user + " has renamed the method '" + oldMethodName + "' to '" + newMethodName + "' in class '" + className + "'.";
		cmd = "<li > <font color='orange' size='1'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}
	this.highlightMethod = function(modelName, className, methodName, user) {
		var model = this.getModel(modelName);
		// var view = model.getView(viewName);
		var classObj = model.getClass(className);
		var method = classObj.methods.getMember(methodName);
		if(method) {
			method.isHighlighted = true;
			method.userName = user;
			var views = model.views;
			var i = 0;
			for( i = 0; i < views.length; i++) {
				if(that.isModelViewInFocus(model, views[i])) {
					var classShape = views[i].getClass(className);
					if(classShape) {
						classShape.update();
					}
				}
			}
		}

	}
	this.unHighlightMethod = function(modelName, className, methodName, user) {
		var model = this.getModel(modelName);
		// var view = model.getView(viewName);
		var classObj = model.getClass(className);
		var method = classObj.methods.getMember(methodName);
		if(method) {
			method.isHighlighted = false;
			var views = model.views;
			var i = 0;
			for( i = 0; i < views.length; i++) {
				if(that.isModelViewInFocus(model, views[i])) {
					var classShape = views[i].getClass(className);
					if(classShape) {
						classShape.update();
					}
				}
			}
		}

	}
	this.renameAttInClass = function(modelName, viewName, className, oldAttName, newAttName, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		var classShape = view.getClass(className);
		var att = classShape.attributes.memberArray.getMember(oldAttName);
		att.name = newAttName;
		att.isHighlighted = false;
		// var att = classShape.attributes.getMember(oldAttName);
		// att.setName(newAttName);

		var isInFocus = false;
		for( i = 0; i < model.views.length; i++) {
			classShape = model.views[i].getClass(className);
			if(classShape) {
				if(that.isModelViewInFocus(model, model.views[i])) {
					//that.unHighlightClass(modelName, newClassName);
					classShape.update();
					//view.update();
					isInFocus = true;
				}
			}
		}
		if(!(isInFocus)) {
			that.highlightAttribute(modelName, className, newAttName, user);
		}

		// if(that.isModelViewInFocus(model, view)) {
		// classShape.update();
		// } else {
		// that.highlightAttribute(modelName, className, newAttName, user);
		// }
		// that.unHighlightClass(modelName, className);
		var cmd = user + " has renamed the attribute '" + oldAttName + "' to '" + newAttName + "' in class '" + className + "'.";
		cmd = "<li > <font color='orange' size='1'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}
	this.highlightAttribute = function(modelName, className, methodName, who) {
		var model = this.getModel(modelName);
		// var view = model.getView(viewName);
		var classObj = model.getClass(className);
		var att = classObj.attributes.getMember(methodName);
		if(att) {
			att.isHighlighted = true;
			att.userName = who;
			var views = model.views;
			var i = 0;
			for( i = 0; i < views.length; i++) {
				if(that.isModelViewInFocus(model, views[i])) {
					var classShape = views[i].getClass(className);
					if(classShape) {
						classShape.update();
					}
				}
			}
		}

	}
	this.unHighlightAttribute = function(modelName, className, methodName, who) {
		var model = this.getModel(modelName);
		// var view = model.getView(viewName);
		var classObj = model.getClass(className);
		var att = classObj.attributes.getMember(methodName);
		if(att) {
			att.isHighlighted = false;
			var views = model.views;
			var i = 0;
			for( i = 0; i < views.length; i++) {
				if(that.isModelViewInFocus(model, views[i])) {
					var classShape = views[i].getClass(className);
					if(classShape) {
						classShape.update();
					}
				}
			}
		}
	}
	this.addClassObjToView = function(modelName, viewName, classObjName, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		view.addClassObj(model.getClass(classObjName));
		if(that.isModelViewInFocus(model, view)) {
			view.update();
		} else {
			view.getClass(classObjName).highlight(user);
		}

		var cmd = user + " has added the class '" + classObjName + "' to th view '" + viewName + "'";
		cmd = "<li > <font color='green' size='2'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}
	this.addRelation = function(modelName, viewName, fromClassName, toClassName, type, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		view.addRelation(view.getClass(fromClassName), view.getClass(toClassName), type);
		if(that.isModelViewInFocus(model, view)) {
			view.update();
		} else {
			this.highlightRelationTitle(modelName, fromClassName, toClassName);
		}

		var cmd = user + " has added a relation of type '" + type + "' from '" + fromClassName + "' to '" + toClassName + "'.";
		cmd = "<li > <font color='green' size='1'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);

	}
	this.setRelationTitle = function(modelName, viewName, fromClassName, toClassName, title, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		var fromClass = view.getClass(fromClassName);
		var toClass = view.getClass(toClassName);
		view.relations.getRelation(fromClass, toClass).setName(title);
		if(that.isModelViewInFocus(model, view)) {
			view.updateRelations();
		} else {
			// view.relations.getRelation(fromClass, toClass).relationObj.isHighlighted=true;
			this.highlightRelationTitle(modelName, fromClassName, toClassName);
		}

		var cmd = user + " has renamed the title of the relation '" + fromClassName + "'->'" + toClassName + "' to '" + title + "'.";
		cmd = "<li > <font color='orange' size='1'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}
	this.highlightRelationTitle = function(modelName, fromClassName, toClassName) {
		var model = this.getModel(modelName);
		var fromClassObj = model.getClass(fromClassName);
		var toClassObj = model.getClass(toClassName);
		model.relations.getRelation(fromClassObj, toClassObj).isHighlighted = true;
		that.currentModel.currentView.update();
		that.currentModel.currentView.updateRelations();
	}
	this.addView = function(modelName, viewName, switchToNewView, user) {
		var model = this.getModel(modelName);
		model.addView(viewName, switchToNewView);
		var cmd = user + " has added a view '" + viewName + "' to the model.";
		cmd = "<li > <font color='green' size='3'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}
	this.highlightClass = function(modelName, classObjName, who) {
		var model = this.getModel(modelName);
		var views = model.views;
		var i = 0;
		for( i = 0; i < views.length; i++) {
			var classShape = views[i].getClass(classObjName);
			if(classShape) {
				classShape.highlight(who);
			}
		}
	}

	this.unHighlightClass = function(modelName, classObjName) {
		var model = this.getModel(modelName);
		var views = model.views;
		var i = 0;
		for( i = 0; i < views.length; i++) {
			var classShape = views[i].getClass(classObjName);
			if(classShape) {
				classShape.unHighlight();
			}
		}
	}
	this.moveClass = function(modelName, viewName, className, shiftX, shiftY) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		var classShape = view.getClass(className);
		classShape.headerRect.x = classShape.headerRect.x + shiftX;
		classShape.headerRect.y = classShape.headerRect.y + shiftY;
		classShape.anchor.x = classShape.anchor.x + shiftX;
		classShape.anchor.y = classShape.anchor.y + shiftY;

		if(that.isModelViewInFocus(model, view)) {
			classShape.update();
		}

	}
	this.removeRelation = function(modelName, viewName, fromClassName, toClassName, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		var fromClass = view.getClass(fromClassName);
		var toClass = view.getClass(toClassName);
		view.removeRelation(fromClass, toClass);
		if(that.isModelViewInFocus(model, view)) {
			view.update();
			view.updateRelations();
		}

		var cmd = user + " has removed the relation '" + fromClassName + "' to '" + toClassName + "'.";
		cmd = "<li > <font color='red' size='1'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}

	this.unHighlightRelationTitle = function(modelName, fromClassName, toClassName) {
		var model = this.getModel(modelName);
		var fromClassObj = model.getClass(fromClassName);
		var toClassObj = model.getClass(toClassName);
		if(that.currentModel) {
			if(that.currentModel.currentView) {
				if((that.currentModel.currentView.getClass(fromClassName) != null) && (that.currentModel.currentView.getClass(toClassName))) {
					model.relations.getRelation(fromClassObj, toClassObj).isHighlighted = false;
					that.currentModel.currentView.update();
					that.currentModel.currentView.updateRelations();
				}
			}
		}

	}
	this.highlightRelationFromNum = function(modelName, fromClassName, toClassName) {
		var model = this.getModel(modelName);
		var fromClassObj = model.getClass(fromClassName);
		var toClassObj = model.getClass(toClassName);
		model.relations.getRelation(fromClassObj, toClassObj).isFromNumHighlighted = true;
		that.currentModel.currentView.update();
		that.currentModel.currentView.updateRelations();
	}
	this.unHighlightRelationFromNum = function(modelName, fromClassName, toClassName) {
		var model = this.getModel(modelName);
		var fromClassObj = model.getClass(fromClassName);
		var toClassObj = model.getClass(toClassName);
		if(that.currentModel) {
			if(that.currentModel.currentView) {
				if((that.currentModel.currentView.getClass(fromClassName) != null) && (that.currentModel.currentView.getClass(toClassName))) {
					model.relations.getRelation(fromClassObj, toClassObj).isFromNumHighlighted = false;
					that.currentModel.currentView.update();
					that.currentModel.currentView.updateRelations();
				}
			}
		}

	}
	this.setRelationFromNum = function(modelName, viewName, fromClassName, toClassName, num, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		var fromClass = view.getClass(fromClassName);
		var toClass = view.getClass(toClassName);
		view.relations.getRelation(fromClass, toClass).setFromNum(num);
		if(that.isModelViewInFocus(model, view)) {
			view.updateRelations();
		} else {
			this.highlightRelationFromNum(modelName, fromClassName, toClassName);
		}

		var cmd = user + " has set the numiricity of class '" + fromClassName + "' in its relation with '" + toClassName + "' to '" + num + "'.";
		cmd = "<li > <font color='orange' size='1'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}

	this.highlightRelationToNum = function(modelName, fromClassName, toClassName) {
		var model = this.getModel(modelName);
		var fromClassObj = model.getClass(fromClassName);
		var toClassObj = model.getClass(toClassName);
		model.relations.getRelation(fromClassObj, toClassObj).isToNumHighlighted = true;
		that.currentModel.currentView.update();
		that.currentModel.currentView.updateRelations();
	}
	this.unHighlightRelationToNum = function(modelName, fromClassName, toClassName) {
		var model = this.getModel(modelName);
		var fromClassObj = model.getClass(fromClassName);
		var toClassObj = model.getClass(toClassName);
		if(that.currentModel) {
			if(that.currentModel.currentView) {
				if((that.currentModel.currentView.getClass(fromClassName) != null) && (that.currentModel.currentView.getClass(toClassName))) {
					model.relations.getRelation(fromClassObj, toClassObj).isToNumHighlighted = false;
					that.currentModel.currentView.update();
					that.currentModel.currentView.updateRelations();
				}
			}
		}

	}
	this.setRelationToNum = function(modelName, viewName, fromClassName, toClassName, num, user) {
		var model = this.getModel(modelName);
		var view = model.getView(viewName);
		var fromClass = view.getClass(fromClassName);
		var toClass = view.getClass(toClassName);
		view.relations.getRelation(fromClass, toClass).setToNum(num);
		if(that.isModelViewInFocus(model, view)) {
			view.updateRelations();
		} else {
			this.highlightRelationToNum(modelName, fromClassName, toClassName);
		}

		var cmd = user + " has set the numiricity of class '" + toClassName + "' in its relation with '" + fromClassName + "' to '" + num + "'.";
		cmd = "<li > <font color='orange' size='1'>" + cmd + "</font></li>";
		model.addConsoleString(cmd);
	}
	this.chat = function(modelName, string) {
		var model = this.getModel(modelName);
		model.addChatString("<li > <font color='#C7D0DB' size='2'>" + string + "</font></li>");
	}

	this.run = function(command) {
		command.userName = that.userName;
		that.webSocket.emit("command", command);
	}
	this.showIntent = function(command) {
		// command.userName = that.userName;
		command.arguments[command.arguments.length] = that.userName;
		that.webSocket.emit("intent", command);
	}
	this.execute = function(name) {
		this[name].apply(this, [].slice.call(arguments, 1)[0]);
		that.webSocket.emit("setLastExecutedCommand", {
			userName : that.userName,
			lastExecutedCommand : that.lastExecutedCommand
		});
	};
	this.webSocket = io.connect("http://localhost:3000");
	this.isConnected = false;
	this.isReconnect = false;
	this.webSocket.on('connect', function() {
		// $('#messages').append('<li>Connected to the server.</li>');
		that.webSocket.emit("getCommands", {
			userName : that.userName
		});
		console.log("connected");
		if(that.isConnected) {
			that.isReconnect = true;
		}
		that.isConnected = true;
	});

	this.webSocket.on('command', function(command) {
		if(command.name == "addModel") {
			var index = command.arguments.length;
			command.arguments[index] = false;
			if(command.userName == that.userName) {
				command.arguments[index] = true;
			}
		}
		if(command.name == "addView") {
			var index = command.arguments.length;
			command.arguments[index] = false;
			if(command.userName == that.userName) {
				command.arguments[index] = true;
			}
		}
		command.arguments[command.arguments.length] = command.userName;
		switch(command.name) {
			case "setRelationToNum" :
			case "setRelationFromNum":
			case "moveClass":
			case  "removeRelation":
			case  "setRelationTitle":
			case  "addRelation":
			case  "addClassObjToView":
			case  "renameAttInClass":
			case  "renameMethodInClass":
			case  "removeAttFromClass":
			case  "removeMethodFromClass":
			case  "addAttToClass":
			case  "addMethodToClass" :
			case "removeClassFromView":
			case  "renameClass" :
			case "addNewClassToView":
			case "addView":
			case "removeClassFromModel":
				var model = that.getModel(command.arguments[0]);
				if(that.currentModel) {
					if(that.currentModel.name == model.name) {
						if(model.isInReplay) {
							model.addCommand(command);
						} else {
							that.lastExecutedCommand = command.seqNumber;
							that.execute(command.name, command.arguments);
						}
					} else {
						that.lastExecutedCommand = command.seqNumber;
						that.execute(command.name, command.arguments);
					}
				} else {
					that.lastExecutedCommand = command.seqNumber;
					that.execute(command.name, command.arguments);
				}

				break;
			default:
				that.lastExecutedCommand = command.seqNumber;
				that.execute(command.name, command.arguments);
				break;
		}

		// if(!(that.inReplay)) {
		// that.execute(command.name, command.arguments);
		// that.lastExecutedCommand = command.seqNumber;
		// that.webSocket.emit("lastExecutedCommand", {
		// commandNumber : command.seqNumber,
		// userName : that.userName
		// });
		// } else {
		// that.tempCommands[that.tempCommands.length] = command;
		// }

	});
	this.webSocket.on('intent', function(command) {
		// console.log(command);
		// $('#messages').append('<li>' + message + '</li>');
		if(!(that.inReplay)) {
			that.execute(command.name, command.arguments);
		}

	});

	this.webSocket.on('disconnect', function() {
		// $('#messages').append('<li>Disconnected from the server.</li>');
		console.log("disconnected");
	});

	this.lastServerCommand = -1;
	this.webSocket.on('commands', function(commands) {
		// that.webSocket.emit("getLastExecutedCommand", {
		// userName : that.userName
		// });
		console.log(commands.lastExecutedCommand);
		var tempCommand;
		var k = 0;
		var l = 0;
		for( k = 0; k < commands.cmds.length; k++) {
			for( l = 1; l < commands.cmds.length - k; l++) {
				if(commands.cmds[l-1].seqNumber>commands.cmds[l].seqNumber)
				{
					tempCommand=commands.cmds[l-1]
					commands.cmds[l-1]=commands.cmds[l];
					commands.cmds[l]=tempCommand;
				}
			}
		}
		that.lastServerCommand = commands.lastExecutedCommand;
		if(!(that.isReconnect)) {
			var i = 0;
			for( i = 0; i < commands.cmds.length; i++) {
				var command = commands.cmds[i];
				// console.log(command);
				if(command.name == "addModel") {
					var index = command.arguments.length;
					command.arguments[index] = false;
					if(command.userName == that.userName) {
						command.arguments[index] = true;
					}
				}
				if(command.name == "addView") {
					var index = command.arguments.length;
					command.arguments[index] = false;
					if(command.userName == that.userName) {
						command.arguments[index] = true;
					}
				}
				command.arguments[command.arguments.length] = command.userName;

				switch(command.name) {
					case "setRelationToNum" :
					case "setRelationFromNum":
					case "moveClass":
					case  "removeRelation":
					case  "setRelationTitle":
					case  "addRelation":
					case  "addClassObjToView":
					case  "renameAttInClass":
					case  "renameMethodInClass":
					case  "removeAttFromClass":
					case  "removeMethodFromClass":
					case  "addAttToClass":
					case  "addMethodToClass" :
					case "removeClassFromView":
					case  "renameClass" :
					case "addNewClassToView":
					case "addView":
					case "removeClassFromModel":
						var model = that.getModel(command.arguments[0]);
						model.addCommand(command);
						break;
					default:
						that.lastExecutedCommand = command.seqNumber;
						that.execute(command.name, command.arguments);
						break;
				}
			}
		} else {
			var i = 0;
			var j = 0;
			for( i = 0; i < commands.cmds.length; i++) {
				if(commands.cmds[i].seqNumber == that.lastServerCommand) {
					j = i;
					break;
				}
			}
			for( i = j + 1; i < commands.cmds.length; i++) {
				var command = commands.cmds[i];
				that.lastExecutedCommand = command.seqNumber;
				that.execute(command.name, command.arguments);
			}
			console.log("reconnected successfully");
		}
	});

	$("input#unhighlightAll").click(function(event) {
		// that.tempLastExecutedCommand=that.tempLastExecutedCommand+1;
		var currentModel = that.currentModel;
		if(currentModel) {
			var currentView = that.currentModel.currentView;
			if(currentView) {
				currentView.removeGhosts();
				var currentClasses = currentModel.classes;
				var i = 0;
				for( i = 0; i < currentClasses.length; i++) {
					console.log(currentModel.name);
					console.log(currentClasses[i].name);
					console.log();
					that.unHighlightClass(currentModel.name, currentClasses[i].name);
					var methods = currentClasses[i].methods.members;
					var j = 0;
					for( j = 0; j < methods.length; j++) {
						methods[j].isHighlighted = false;
					}

					var atts = currentClasses[i].attributes.members;
					for( j = 0; j < atts.length; j++) {
						atts[j].isHighlighted = false;
					}
				}
				var relations = currentView.relations.relationObjArray.members;
				for( i = 0; i < relations.length; i++) {
					that.unHighlightRelationTitle(currentModel.name, relations[i].fromClass.name, relations[i].toClass.name);
					that.unHighlightRelationFromNum(currentModel.name, relations[i].fromClass.name, relations[i].toClass.name);
					that.unHighlightRelationToNum(currentModel.name, relations[i].fromClass.name, relations[i].toClass.name);
				}
				currentView.update();
				currentView.updateRelations();
			}
		}
	});
	this.globalEscape = function(event) {
		// alert("Pressed " + event.keyCode);
		if(event.which == 27) {
			var e = jQuery.Event("keydown");
			e.which = 27;
			// alert("escape has been clicked");
			if($('#memberName').length !== 0) {
				$('#memberName').trigger(e);
			}
			if($('#className').length !== 0) {
				$("#className").trigger(e);
			}

			if($('#titleName').length !== 0) {
				$('#titleName').trigger(e);
			}
			if($('#fromNum').length !== 0) {
				$('#fromNum').trigger(e);
			}
			if($('#toNum').length !== 0) {
				$('#toNum').trigger(e);
			}
			if(that.currentModel) {
				var i = 0;
				for( i = 0; i < that.currentModel.relations.members.length; i++) {
					that.currentModel.relations.members[i].isSelected = false;
				}
				if(that.currentModel.currentView) {
					that.currentModel.currentView.globalEscape();
					that.currentModel.currentView.update();
					that.currentModel.currentView.updateRelations();
				}
			}
		} else if(event.which == 46)//delete
		{
			if(that.currentModel) {
				var i = 0;
				for( i = 0; i < that.currentModel.relations.members.length; i++) {
					if(that.currentModel.relations.members[i].isSelected) {
						var j = 0;
						for( j = 0; j < that.currentModel.views.length; j++) {
							if(that.currentModel.views[j].getClass(that.currentModel.relations.members[i].fromClass.name)) {
								if(that.currentModel.views[j].getClass(that.currentModel.relations.members[i].toClass.name)) {
									var command = {
										name : "removeRelation",
										arguments : [that.currentModel.name, that.currentModel.views[j].name, that.currentModel.relations.members[i].fromClass.name, that.currentModel.relations.members[i].toClass.name]
									}
									that.run(command);
									return;
								}
							}
						}

					}
				}
			}
		}
	}
	$("#canvasContainer").keydown(function(event) {
		that.globalEscape(event);
	});
}